$$.sql.Pagination = function(){
	/**
	 * 每页显示记录笔数，或者说读取多少笔的记录。如不指定则为pageSize。
	 * @type {Number} pageSize
	 */
	this.pageSize = Number(Request.QueryString('start')()) || 8;

	/**
	 * 如不指定则为零，表示从第一笔记录开始。
	 * @type {Number} startNum
	 */
	this.startNum = Number(Request.QueryString('start')()) || 0;
	
	/**
	 * 符合当前查询条件的记录数。
	 * @type {Number} totalCount。
	 */
	this.totalCount = 0;
	
	/**
	 * 符合当前查询条件的总页数 = totalCount / pageSize
	 * @type {Number}
	 */
	this.pages = 0;
	
	/**
	 * 页码
	 * @type {Number} page
	 */
	this.pageNo = null;
	
	/**
	 * 使用预搜索。
	 * Why？
	 * 结论1：Select * 语句对速度影响很大。
	 * select * from Adab 用时：35940  (共57个字段)
	 * select xhjm,xm,xjztdm,bdm,nj,dwdm from Adab  用时 4186
	 * select xhjm,xm  from Adab  用时1626
	 * select xm from Adab   用时830
	 * 可以看得出每增加一个字段，时间会增加几乎是一倍。
	 * 另外，返回的数据的长度也会影响时间：如 select sfzh from Adab 用时1580 几乎与select xhjm,xm from Adab相同。
	 * 因此，返回的数据量是影响速度最关键的因素。网络上的数据传送成了执行SQL最大的性能问题。
	 * 执行一个selec dwdm,count(xhjm) from Adab的语句，用时106 要汇总计算，但传送数据少，因此速度很快。
	 * @ASP Only
	 * @param  {String} id_fieldName 排序的字段
	 * @return {Object} pagination
	 */
	var 
	 removeFields	= /(?:SELECT)\s+(.*)\s+(?:FROM)\s+(.+)\s?/i
	,hasSort		= /(\s+ORDER\s+BY\s+[\w\.]+)\s?(ASC|DESC)?/i
	,hasWhere		= /\s+WHERE\s+/i;

	/**
	 * 优化一下，先不要id选好记录，选好后，跳到那一页，根据id读取。
	 * @static
	 * @private
	 * @ASP Only
	 * @return {String}
	 */
	function getQuickSql(querySql){
		if(!querySql){
			throw '没有查询的SQL！';
		}
		
   		var arr	= querySql.match(removeFields);
   		
   		var idField	= 'edk_news.id'; /* id only. like 'edk_news.ID' */
		
		if(!arr || arr.length < 2){
			throw '不能获取正确的查询字段';
		}
		
		/**
		 * 保存欲查询的SQL，即分页前的SQL。
		 * @type {String}
		 */
		this.querySql = querySql;
		
		return querySql.replace(arr[1], idField);
	}
	    
    /**
     * @private
     * @ASP Only
     * @param   {ado.rs} rs
     * @param	{String} querySql
     * @return  {String}
     */
    function getCurrentSql(rs, querySql){
		var IDs = [], i = 0;
		
		do {
			i++;
			IDs.push(rs('id').value);
			rs.movenext();
		}while (!rs.Eof && ( i < rs.pageSize));
		
		IDs	= (hasWhere.test(querySql) ?　" WHERE " : " WHERE ") + "  edk_news.ID = " + IDs.join(' OR edk_news.ID = ')
		
		if(!hasSort.test(querySql)){
			 return querySql + IDs;
		}else{
			 IDs += " $1 ASC "; // 必须相反，与原来的ORDER BY！
			 return querySql.replace(hasSort, IDs);  
		}
    }
    
	/**
	 * 分页的核心函数，返回 pagination 对象。转换 start/limit 分页方式 为 ado 的 absolutepage/pagesize 分页。
	 * @param  {Number} start
	 * @param  {Number}	pageSize
	 * @param  {Number}	totalCount
	 * @return {Object}
	 * @private
	 * @static
	 */
	function page(start, pageSize, totalCount){
		var 
		 // 计算分页总数。
		 pages = totalCount % pageSize ? Math.floor(totalCount / pageSize) + 1 : totalCount / pageSize
	     // 获取当前的页码。通过 start 计算得在第几页。
	    ,pageNo  = start / pageSize + 1
		/*
		 // pageNo的另一种解法
		var	 
			 pageNo		= (this.startNum / pageSize) + 1
			,pageNo		= pageNo || 1
			,pageNo		= (pageNo - totalCount) > 0 ? totalCount : pageNo
		*/
		,lastOffset = (pageNo - 2) * pageSize
		,isBOF		= lastOffset < 0
		,isEOF		= (pageNo * pageSize) > totalCount
		,nextOffset = isEOF ? (pageNo - 1) * pageSize : (pageNo * pageSize);

		return {
			 totalCount	: totalCount		// 符合条件的记录总数。
			,start		: start				// 从第几笔记录开始偏移（offset）。
			,pageSize	: pageSize			// 每页多少笔记录？也可以认为是 偏移数 
			,pageNo		: pageNo			// 当前页码，即第几页。
			,pages		: pages				// 总页数。
			,lastOffset : lastOffset		// 跳到前一页（offset的方式）
			,nextOffset : nextOffset		// 跳到后一页（offset的方式）
			,isBOF		: isBOF				// 是否在最头一页（boolean）
			,isEOF		: isEOF				// 是否在最尾一页（boolean）
		};
	}
	
	/**
	 * @param {String} querySql
	 */
	this.renderPage = function(querySql, id_fieldName){
		var 
		// 为求记录总数而优化的SQL，即分页后的SQL。当前页数据的SQL
		 rs		  = new ActiveXObject("ADODB.Recordset")
		,quickSql = getQuickSql.call(this, querySql);
		
		rs.Open(quickSql, this.getConnObj(), 1 ,1);
		
		if(rs.EOF && rs.BOF){
			Response.write('没有记录');
			throw '没有记录';
		}else{
			var
		     pagination 	 = page(this.startNum, this.pageSize, rs.recordcount)
		    ,uiBar			 = $$.sql.Pagination.barController
		    ,currentPageSql;
		    
			 rs.pagesize     = pagination.pageSize
			,rs.absolutepage = pagination.pageNo
		    ,currentPageSql	 = getCurrentSql(rs, this.querySql); // 求当前页数据的SQL。
		    
		    rs.close();
		    
		    for(var i in pagination)uiBar[i] = pagination[i];
		}
		
	    return {
	         sql 	: currentPageSql
	        ,count  : pagination.totalCount
	        , html  : uiBar.render()
	    };  
	}
		
}

/**
 * This is a controller.
 * @class $$.sql.reader.Pagination.barController
 */
$$.sql.Pagination.barController = {
	/**
	 * 返回true表示存在除了start以外还有其他的参数。
	 * @return {Boolean}
	 */
     hasQueryStr : function (){
        var req = Request.QueryString;
        if(req.Count > 0){
            if(req.Count == 1 && req('start').Count){
                return false; // 只有 start 的参数
            }
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * 返回QueryString
     * @todo
     * @return {String}
     */
    ,getQueryString : function (){
        var arr = [], QueryObj = {};
        
        var key, v;
        for(var e = new Enumerator(Request.QueryString); !e.atEnd(); e.moveNext()){
            key = e.item().toString();
            v   = Request.QueryString(key)(); // MS ASP这里好奇怪，不加()不能返回字符串
        
            /*
            v = unescape(decodeURI(v));
            
            if( v == 'true' )  v = true;
            if( v == 'false' ) v = false;
            */
            //if(isNum.test(v))  v = Number(v);
            
            QueryObj[key] = v;
        }
        if( QueryObj.start || QueryObj.start === 0 ){
            delete QueryObj.start;
        }
        for(var i in QueryObj){
            arr.push(i + '=' + QueryObj[i]);
        }
        return arr.join('&');        
    }
    
	/**
	 * @private
	 * @type {String}
	 */
	,el : '<li><a href="{0}" title="{1}">{2}</a></li>'
	
    // 上一页
    ,renderBOF : function(){
        var urlP = "?start={0}";
        
        if(this.hasQueryStr()){
            urlP += "&" + this.getQueryString(); 
        }
        
	    if(this.isBOF){
	    	return this.el.format(urlP.format(0), "首页" , "首页");
	    }else{
	    	return this.el.format(urlP.format(this.lastOffset), "下一页", "前页");
	    }
    }
                
    // 下一页
    ,renderEOF : function(){
        var urlP = "?start={0}";
        
        if(this.hasQueryStr()){
            urlP += "&" + this.getQueryString(); 
        }
           
	    if(this.isEOF){
	    	return this.el.format(urlP.format(this.nextOffset), "末页" , "末页");
	    }else{
	    	return this.el.format(urlP.format(this.nextOffset), "后一页", "后页");
	    }
    }

    ,renderBar : function(){
        var link = {
             href   : "?start={0}"
            ,title  : ""
            ,text   : ""
        };
        if(this.hasQueryStr()){
            link.href += "&" + this.getQueryString(); 
        }
        
        var e, html, links = [];
        var page;
        for(var i = 0, j = this.pages; i < j; i++){
            page    = i + 1;
            e       = {};
            
            for(var i in link){
            	e[i]= link[i];
            }
            e.href  = e.href.format( i * this.pageSize); // 倍数关系
            e.text  = page;
            e.title = "-->" + page;
            
            html    = this.el.format(e.href, e.title, e.text);
            
            if(page == this.pageNo){
                html = html.replace("<li", "<li class=\"highlight\"");
            }
            links.push(html);
        }
        return links.join('\n');
    }
    
	/**
	 * @return {String}
	 */
	,render : function(){
	    this.el = this.renderBOF() + this.renderBar() + this.renderEOF();
	    return $$.tpl.fillData($$.cfg.edk.edk_tpl.selectSingleNode('//pagingBar/div').xml, this);
	}
};